<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0"    <title>DormDB - 数据库自助申请平台</title>
    <!-- TailwindCSS -->
    <script src="https://cdn.tailwindcss.com"></script>
    <!-- Font Awesome -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <!-- Vue 3 -->
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <!-- Axios for HTTP requests -->
    <script src="https://cdn.jsdelivr.net/npm/axios@1.6.0/dist/axios.min.js"></script>
    <!-- Google Fonts -->
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
    <style>
        body {
            font-family: 'Inter', sans-serif;
        }
        
        .gradient-bg {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        }
        
        .glass-effect {
            background: rgba(255, 255, 255, 0.95);
            backdrop-filter: blur(20px);
            border: 1px solid rgba(255, 255, 255, 0.2);
        }
        
        .floating-animation {
            animation: float 6s ease-in-out infinite;
        }
        
        @keyframes float {
            0%, 100% { transform: translateY(0px) rotate(0deg); }
            50% { transform: translateY(-20px) rotate(10deg); }
        }
        
        .fade-in {
            animation: fadeIn 0.8s ease forwards;
        }
        
        @keyframes fadeIn {
            from {
                opacity: 0;
                transform: translateY(30px);
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }
        
        .gradient-text {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            background-clip: text;
        }
        
        .btn-gradient {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            transition: all 0.3s ease;
        }
        
        .btn-gradient:hover {
            transform: translateY(-2px);
            box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4);
        }
        
        .shake {
            animation: shake 0.5s ease-in-out;
        }
        
        @keyframes shake {
            0%, 100% { transform: translateX(0); }
            25% { transform: translateX(-5px); }
            75% { transform: translateX(5px); }
        }
        
        .pulse-animation {
            animation: pulse 2s infinite;
        }
        
        @keyframes pulse {
            0% { transform: scale(1); }
            50% { transform: scale(1.05); }
            100% { transform: scale(1); }
        }
    </style>
</head>
<body class="gradient-bg min-h-screen">
    <div id="app">
        <!-- 浮动装饰元素 -->
        <div class="fixed inset-0 pointer-events-none z-0">
            <div class="absolute w-20 h-20 bg-white bg-opacity-10 rounded-full top-1/5 left-1/12 floating-animation"></div>
            <div class="absolute w-30 h-30 bg-white bg-opacity-10 rounded-full top-3/5 right-1/12 floating-animation" style="animation-delay: 2s;"></div>
            <div class="absolute w-16 h-16 bg-white bg-opacity-10 rounded-full bottom-1/5 left-1/5 floating-animation" style="animation-delay: 4s;"></div>
        </div>
        
        <!-- 主容器 -->
        <div class="container mx-auto px-4 py-8 relative z-10">
            <div class="max-w-2xl mx-auto glass-effect rounded-3xl shadow-2xl overflow-hidden fade-in">
                <!-- 顶部装饰条 -->
                <div class="h-1 bg-gradient-to-r from-pink-400 to-red-400"></div>
                
                <!-- 内容区域 -->
                <div class="p-8 md:p-12">
                    <!-- 应用头部 -->
                    <div class="text-center mb-8">
                        <i class="fas fa-database text-6xl gradient-text mb-4 pulse-animation"></i>
                        <h1 class="text-4xl md:text-5xl font-bold gradient-text mb-2">DormDB</h1>
                        <p class="text-gray-600 text-lg">数据库自助申请平台</p>
                    </div>
                    
                    <!-- 申请表单 -->
                    <form @submit.prevent="submitApplication" class="space-y-6">
                        <div class="relative">
                            <div class="relative">
                                <input 
                                    v-model="identityKey"
                                    type="text" 
                                    id="identityKey"
                                    class="w-full px-4 py-4 text-lg border-2 border-gray-200 rounded-xl bg-gray-50 focus:bg-white focus:border-indigo-500 focus:outline-none transition-all duration-300"
                                    :class="{ 'border-red-500 shake': validationError, 'border-green-500': isValid && identityKey }"
                                    placeholder="请输入您的学号，例如：20250701"
                                    required
                                >
                                <label for="identityKey" class="absolute -top-2 left-3 bg-white px-2 text-sm font-medium text-gray-700">
                                    身份标识 (学号)
                                </label>
                            </div>
                            <div class="flex items-center mt-2 text-sm text-gray-600">
                                <i class="fas fa-info-circle mr-2 text-blue-500"></i>
                                <span>请输入您的学号或唯一身份标识，只能包含字母、数字和下划线</span>
                            </div>
                            <div v-if="validationError" class="mt-2 text-sm text-red-600">
                                <i class="fas fa-exclamation-triangle mr-1"></i>
                                {{ validationError }}
                            </div>
                        </div>
                        
                        <button 
                            type="submit" 
                            :disabled="isLoading || !identityKey"
                            class="w-full py-4 px-6 text-white text-lg font-semibold rounded-xl btn-gradient disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center space-x-2"
                        >
                            <i v-if="isLoading" class="fas fa-spinner fa-spin"></i>
                            <i v-else class="fas fa-paper-plane"></i>
                            <span>{{ isLoading ? '申请中...' : '申请数据库' }}</span>
                        </button>
                    </form>
                    
                    <!-- 加载状态 -->
                    <div v-if="isLoading" class="mt-8 text-center py-8">
                        <div class="inline-block w-12 h-12 border-4 border-indigo-200 border-t-indigo-600 rounded-full animate-spin mb-4"></div>
                        <p class="text-gray-600 text-lg font-medium">正在为您创建专属数据库...</p>
                    </div>
                    
                    <!-- 结果显示 -->
                    <div v-if="result" class="mt-8">
                        <!-- 成功结果 -->
                        <div v-if="result.success" class="bg-green-50 border border-green-200 rounded-2xl overflow-hidden">
                            <div class="bg-green-100 px-6 py-4 border-b border-green-200">
                                <h3 class="text-lg font-semibold text-green-800 flex items-center">
                                    <i class="fas fa-check-circle mr-2 text-xl"></i>
                                    数据库创建成功！
                                </h3>
                                <p class="text-green-700 mt-1">您的专属数据库已成功创建，请妥善保存以下连接信息。</p>
                            </div>
                            
                            <!-- 凭证信息 -->
                            <div class="p-6 space-y-4">
                                <div v-for="(value, key) in credentials" :key="key" class="bg-white rounded-lg border border-gray-200 p-4">
                                    <label class="block text-sm font-medium text-gray-700 mb-2">{{ getCredentialLabel(key) }}</label>
                                    <div class="flex items-center space-x-2">
                                        <input 
                                            :value="value" 
                                            readonly 
                                            class="flex-1 px-3 py-2 bg-gray-50 border border-gray-200 rounded-lg font-mono text-sm"
                                        >
                                        <button 
                                            @click="copyToClipboard(value, key)"
                                            class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition-colors flex items-center space-x-1"
                                        >
                                            <i :class="copyStatus[key] ? 'fas fa-check' : 'fas fa-copy'"></i>
                                            <span>{{ copyStatus[key] ? '已复制' : '复制' }}</span>
                                        </button>
                                    </div>
                                </div>
                                
                                <!-- 连接字符串 -->
                                <div class="bg-blue-50 rounded-lg border border-blue-200 p-4">
                                    <h4 class="text-lg font-semibold text-blue-800 mb-3 flex items-center">
                                        <i class="fas fa-link mr-2"></i>
                                        连接字符串
                                    </h4>
                                    
                                    <div class="space-y-3">
                                        <div>
                                            <label class="block text-sm font-medium text-blue-700 mb-1">MySQL 连接字符串</label>
                                            <div class="flex items-center space-x-2">
                                                <input 
                                                    :value="connectionStrings.mysql" 
                                                    readonly 
                                                    class="flex-1 px-3 py-2 bg-white border border-blue-200 rounded-lg font-mono text-sm"
                                                >
                                                <button 
                                                    @click="copyToClipboard(connectionStrings.mysql, 'mysql')"
                                                    class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors flex items-center space-x-1"
                                                >
                                                    <i :class="copyStatus.mysql ? 'fas fa-check' : 'fas fa-copy'"></i>
                                                    <span>{{ copyStatus.mysql ? '已复制' : '复制' }}</span>
                                                </button>
                                            </div>
                                        </div>
                                        
                                        <div>
                                            <label class="block text-sm font-medium text-blue-700 mb-1">JDBC URL</label>
                                            <div class="flex items-center space-x-2">
                                                <input 
                                                    :value="connectionStrings.jdbc" 
                                                    readonly 
                                                    class="flex-1 px-3 py-2 bg-white border border-blue-200 rounded-lg font-mono text-sm"
                                                >
                                                <button 
                                                    @click="copyToClipboard(connectionStrings.jdbc, 'jdbc')"
                                                    class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors flex items-center space-x-1"
                                                >
                                                    <i :class="copyStatus.jdbc ? 'fas fa-check' : 'fas fa-copy'"></i>
                                                    <span>{{ copyStatus.jdbc ? '已复制' : '复制' }}</span>
                                                </button>
                                            </div>
                                        </div>
                                    </div>
                                    
                                    <div class="mt-4 p-3 bg-yellow-50 border border-yellow-200 rounded-lg">
                                        <p class="text-sm text-yellow-800">
                                            <i class="fas fa-lightbulb mr-1"></i>
                                            建议使用连接字符串进行数据库连接，更加便捷和标准化。
                                        </p>
                                    </div>
                                </div>
                                
                                <!-- 一键复制所有信息 -->
                                <button 
                                    @click="copyAllCredentials"
                                    class="w-full py-3 px-4 bg-gradient-to-r from-purple-600 to-pink-600 text-white rounded-lg hover:from-purple-700 hover:to-pink-700 transition-all flex items-center justify-center space-x-2"
                                >
                                    <i class="fas fa-clipboard-list"></i>
                                    <span>一键复制所有连接信息</span>
                                </button>
                            </div>
                        </div>
                        
                        <!-- 错误结果 -->
                        <div v-else class="bg-red-50 border border-red-200 rounded-2xl p-6">
                            <div class="flex items-center mb-3">
                                <i class="fas fa-exclamation-circle text-2xl text-red-600 mr-3"></i>
                                <h3 class="text-lg font-semibold text-red-800">申请失败</h3>
                            </div>
                            <p class="text-red-700">{{ result.message }}</p>
                        </div>
                    </div>
                    
                    <!-- 重要提示 -->
                    <div class="mt-8 bg-yellow-50 border border-yellow-200 rounded-xl p-6">
                        <div class="flex items-start">
                            <i class="fas fa-exclamation-triangle text-yellow-600 text-xl mr-3 mt-1"></i>
                            <div>
                                <h4 class="font-semibold text-yellow-800 mb-2">重要提示</h4>
                                <ul class="text-sm text-yellow-700 space-y-1">
                                    <li>• 请立即保存数据库连接信息，系统不会再次显示密码</li>
                                    <li>• 建议将密码保存到安全的密码管理器中</li>
                                    <li>• 数据库仅供学习和开发使用，请勿存储敏感信息</li>
                                    <li>• 如有问题，请联系管理员：<a href="mailto:admin@example.com" class="text-yellow-800 underline">admin@example.com</a></li>
                                </ul>
                            </div>
                        </div>
                    </div>
                    
                    <!-- 公开申请记录 -->
                    <div class="mt-8 bg-white rounded-xl border border-gray-200 overflow-hidden">
                        <div class="bg-gray-50 px-6 py-4 border-b border-gray-200">
                            <h3 class="text-lg font-semibold text-gray-800 flex items-center">
                                <i class="fas fa-history mr-2"></i>
                                最近申请记录
                            </h3>
                        </div>
                        <div class="p-6">
                            <div v-if="publicRecords.length === 0" class="text-center py-8 text-gray-500">
                                <i class="fas fa-inbox text-3xl mb-2"></i>
                                <p>暂无申请记录</p>
                            </div>
                            <div v-else class="space-y-3 max-h-64 overflow-y-auto">
                                <div v-for="record in publicRecords" :key="record.id" class="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
                                    <div>
                                        <div class="font-medium text-gray-900">{{ record.identity_key_masked }}</div>
                                        <div class="text-sm text-gray-500">{{ formatTime(record.created_at) }}</div>
                                    </div>
                                    <span :class="getStatusClass(record.status)" class="px-2 py-1 rounded-full text-xs font-medium">
                                        {{ getStatusText(record.status) }}
                                    </span>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                
                <!-- 页脚 -->
                <div class="bg-gray-50 px-8 py-6 border-t border-gray-200 text-center">
                    <p class="text-gray-600 text-sm mb-2">DormDB v1.0.0 | 数据库自助申请平台</p>
                    <div class="flex justify-center space-x-4 text-sm">
                        <a href="/demo.html" class="text-indigo-600 hover:text-indigo-800 transition-colors">
                            <i class="fas fa-play-circle mr-1"></i>演示版本
                        </a>
                        <a href="/admin.html" class="text-indigo-600 hover:text-indigo-800 transition-colors">
                            <i class="fas fa-cog mr-1"></i>管理面板
                        </a>
                        <a href="https://github.com" target="_blank" class="text-indigo-600 hover:text-indigo-800 transition-colors">
                            <i class="fab fa-github mr-1"></i>GitHub
                        </a>
                    </div>
                </div>
            </div>
        </div>
        
        <!-- Toast 通知 -->
        <div class="fixed top-4 right-4 z-50 space-y-2">
            <div v-for="toast in toasts" :key="toast.id" 
                 :class="getToastClass(toast.type)"
                 class="max-w-sm p-4 rounded-lg shadow-lg transform transition-all duration-300 ease-in-out"
            >
                <div class="flex items-center">
                    <i :class="getToastIcon(toast.type)" class="mr-3 text-lg"></i>
                    <div class="flex-1">
                        <p class="font-medium">{{ toast.title }}</p>
                        <p v-if="toast.message" class="text-sm opacity-90">{{ toast.message }}</p>
                    </div>
                    <button @click="removeToast(toast.id)" class="ml-2 opacity-70 hover:opacity-100">
                        <i class="fas fa-times"></i>
                    </button>
                </div>
            </div>
        </div>
    </div>
    
    <script>
        const { createApp, ref, computed, onMounted } = Vue;
        
        createApp({
            setup() {
                // 响应式数据
                const identityKey = ref('');
                const isLoading = ref(false);
                const result = ref(null);
                const validationError = ref('');
                const publicRecords = ref([]);
                const copyStatus = ref({});
                const toasts = ref([]);
                
                // 计算属性
                const isValid = computed(() => {
                    if (!identityKey.value) return false;
                    const pattern = /^[a-zA-Z0-9_]+$/;
                    return pattern.test(identityKey.value) && identityKey.value.length <= 50;
                });
                
                const credentials = computed(() => {
                    if (!result.value?.success || !result.value?.data) return {};
                    const data = result.value.data;
                    return {
                        host: data.db_host,
                        port: data.db_port,
                        database: data.db_name,
                        username: data.username,
                        password: data.password
                    };
                });
                
                const connectionStrings = computed(() => {
                    if (!result.value?.success || !result.value?.data) return {};
                    const data = result.value.data;
                    return {
                        mysql: `mysql://${data.username}:${data.password}@${data.db_host}:${data.db_port}/${data.db_name}`,
                        jdbc: `jdbc:mysql://${data.db_host}:${data.db_port}/${data.db_name}?user=${data.username}&password=${data.password}`
                    };
                });
                
                // 方法
                const validateInput = () => {
                    validationError.value = '';
                    
                    if (!identityKey.value) {
                        validationError.value = '请输入身份标识';
                        return false;
                    }
                    
                    if (!isValid.value) {
                        validationError.value = '身份标识格式无效，只能包含字母、数字和下划线，长度为1-50个字符';
                        return false;
                    }
                    
                    return true;
                };
                
                const submitApplication = async () => {
                    if (!validateInput()) {
                        showToast('输入验证失败', validationError.value, 'error');
                        return;
                    }
                    
                    isLoading.value = true;
                    result.value = null;
                    
                    try {
                        const response = await fetch('/api/v1/apply', {
                            method: 'POST',
                            headers: {
                                'Content-Type': 'application/json',
                            },
                            body: JSON.stringify({
                                identity_key: identityKey.value.trim()
                            })
                        });
                        
                        const data = await response.json();
                        
                        if (data.code === 0) {
                            result.value = {
                                success: true,
                                data: data.data
                            };
                            showToast('申请成功', '数据库创建成功！', 'success');
                            loadPublicRecords(); // 刷新记录
                        } else {
                            result.value = {
                                success: false,
                                message: getErrorMessage(data.code, data.message)
                            };
                            showToast('申请失败', result.value.message, 'error');
                        }
                    } catch (error) {
                        console.error('请求失败:', error);
                        result.value = {
                            success: false,
                            message: '网络请求失败，请检查网络连接后重试'
                        };
                        showToast('网络错误', '请求失败，请重试', 'error');
                    } finally {
                        isLoading.value = false;
                    }
                };
                
                const copyToClipboard = async (text, key) => {
                    try {
                        if (navigator.clipboard && window.isSecureContext) {
                            await navigator.clipboard.writeText(text);
                        } else {
                            // 降级方案
                            const textArea = document.createElement('textarea');
                            textArea.value = text;
                            textArea.style.position = 'fixed';
                            textArea.style.left = '-999999px';
                            document.body.appendChild(textArea);
                            textArea.focus();
                            textArea.select();
                            document.execCommand('copy');
                            textArea.remove();
                        }
                        
                        copyStatus.value[key] = true;
                        showToast('复制成功', '内容已复制到剪贴板', 'success');
                        
                        setTimeout(() => {
                            copyStatus.value[key] = false;
                        }, 2000);
                    } catch (error) {
                        console.error('复制失败:', error);
                        showToast('复制失败', '请手动复制内容', 'error');
                    }
                };
                
                const copyAllCredentials = () => {
                    const creds = credentials.value;
                    const connStrings = connectionStrings.value;
                    
                    const allInfo = `数据库连接信息：
主机地址: ${creds.host}
端口: ${creds.port}
数据库名: ${creds.database}
用户名: ${creds.username}
密码: ${creds.password}

MySQL连接字符串: ${connStrings.mysql}
JDBC URL: ${connStrings.jdbc}`;
                    
                    copyToClipboard(allInfo, 'all');
                };
                
                const loadPublicRecords = async () => {
                    try {
                        const response = await fetch('/api/v1/public/applications');
                        const data = await response.json();
                        
                        if (data.code === 0 && data.data) {
                            publicRecords.value = data.data;
                        }
                    } catch (error) {
                        console.error('加载申请记录失败:', error);
                    }
                };
                
                const showToast = (title, message, type = 'info') => {
                    const id = Date.now();
                    toasts.value.push({ id, title, message, type });
                    
                    setTimeout(() => {
                        removeToast(id);
                    }, 5000);
                };
                
                const removeToast = (id) => {
                    const index = toasts.value.findIndex(toast => toast.id === id);
                    if (index > -1) {
                        toasts.value.splice(index, 1);
                    }
                };
                
                // 工具函数
                const getErrorMessage = (code, message) => {
                    const errorMessages = {
                        40001: '输入的身份标识格式无效，请检查后重试',
                        40901: '该身份标识已经申请过数据库，每个身份标识只能申请一次',
                        50001: '服务器内部错误，请稍后重试或联系管理员',
                        50002: '数据库创建失败，请稍后重试或联系管理员'
                    };
                    return errorMessages[code] || message || '未知错误，请联系管理员';
                };
                
                const getCredentialLabel = (key) => {
                    const labels = {
                        host: '主机地址',
                        port: '端口',
                        database: '数据库名',
                        username: '用户名',
                        password: '密码'
                    };
                    return labels[key] || key;
                };
                
                const getStatusClass = (status) => {
                    const classes = {
                        success: 'bg-green-100 text-green-800',
                        failed: 'bg-red-100 text-red-800',
                        deleted: 'bg-gray-100 text-gray-800'
                    };
                    return classes[status] || 'bg-gray-100 text-gray-800';
                };
                
                const getStatusText = (status) => {
                    const texts = {
                        success: '成功',
                        failed: '失败',
                        deleted: '已删除'
                    };
                    return texts[status] || '未知';
                };
                
                const formatTime = (timeString) => {
                    try {
                        const date = new Date(timeString);
                        const now = new Date();
                        const diff = now - date;
                        
                        if (diff < 60000) return '刚刚';
                        if (diff < 3600000) return `${Math.floor(diff / 60000)}分钟前`;
                        if (diff < 86400000) return `${Math.floor(diff / 3600000)}小时前`;
                        return date.toLocaleDateString('zh-CN');
                    } catch {
                        return '未知时间';
                    }
                };
                
                const getToastClass = (type) => {
                    const classes = {
                        success: 'bg-green-500 text-white',
                        error: 'bg-red-500 text-white',
                        warning: 'bg-yellow-500 text-white',
                        info: 'bg-blue-500 text-white'
                    };
                    return classes[type] || classes.info;
                };
                
                const getToastIcon = (type) => {
                    const icons = {
                        success: 'fas fa-check-circle',
                        error: 'fas fa-exclamation-circle',
                        warning: 'fas fa-exclamation-triangle',
                        info: 'fas fa-info-circle'
                    };
                    return icons[type] || icons.info;
                };
                
                // 生命周期
                onMounted(() => {
                    loadPublicRecords();
                });
                
                return {
                    identityKey,
                    isLoading,
                    result,
                    validationError,
                    publicRecords,
                    copyStatus,
                    toasts,
                    isValid,
                    credentials,
                    connectionStrings,
                    submitApplication,
                    copyToClipboard,
                    copyAllCredentials,
                    removeToast,
                    getCredentialLabel,
                    getStatusClass,
                    getStatusText,
                    formatTime,
                    getToastClass,
                    getToastIcon
                };
            }
        }).mount('#app');
    </script>
</body>
</html>
